package nachos.threads;

import nachos.machine.*;

/**
 * A <i>communicator</i> allows threads to synchronously exchange 32-bit
 * messages. Multiple threads can be waiting to <i>speak</i>,
 * and multiple threads can be waiting to <i>listen</i>. But there should never
 * be a time when both a speaker and a listener are waiting, because the two
 * threads can be paired off at this point.
 */
public class Communicator {

	/**
	 * Allocate a new communicator.
	 */
	public Communicator() {
		hasMessage = false;
		lock = new Lock(); //locks the ability to read
		readWait = new Condition2(lock); //waits for a read to be preformed
		writeWait = new Condition2(lock); //waits for a write to be preformed
		clearWait = new Condition2(lock);
	}

	/**
	 * Wait for a thread to listen through this communicator, and then transfer
	 * <i>word</i> to the listener.
	 *
	 * <p>
	 * Does not return until this thread is paired up with a listening thread.
	 * Exactly one listener should receive <i>word</i>.
	 *
	 * @param	word	the integer to transfer.
	 */
	public void speak(int word) {
		lock.acquire();
		while(hasMessage){
			clearWait.sleep();
		}
		message = word;
		hasMessage = true;
		writeWait.wake();
		readWait.sleep();
		clearWait.wake();
		lock.release();
	}

	/**
	 * Wait for a thread to speak through this communicator, and then return
	 * the <i>word</i> that thread passed to <tt>speak()</tt>.
	 *
	 * @return	the integer transferred.
	 */
	public int listen() {
		lock.acquire();
		while(!hasMessage){
			writeWait.sleep();
		}
		hasMessage = false;
		readWait.wake();
		lock.release();
		return message;
	}
	Lock lock;
	Condition2 writeWait;
	Condition2 readWait;
	Condition2 clearWait;
	boolean hasMessage;
	int message;
}
